<!--
 * Copyright (c) 2022 - present TinyVue Authors.
 * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 -->
<script lang="jsx">
import { $prefix, setup, h } from '@opentiny/vue-common'
import { t } from '@opentiny/vue-locale'
import { renderless, api } from '@opentiny/vue-renderless/tab-nav/vue'
import Popover from '@opentiny/vue-popover'
import { iconChevronLeft, iconChevronRight, iconClose } from '@opentiny/vue-icon'

const getOrderedPanes = (state, panes) => {
  const slotDefault = state.rootTabs.$slots.default
  let orders

  if (typeof slotDefault === 'function') {
    orders = []

    const tabVnodes = slotDefault()
    const handler = ({ type, componentOptions, props }) => {
      let componentName = type && type.componentName

      if (!componentName) componentName = componentOptions && componentOptions.Ctor.extendOptions.componentName

      if (componentName === 'TabItem') {
        const paneName = (props && props.name) || (componentOptions && componentOptions.propsData.name)

        orders.push(paneName)
      }
    }

    tabVnodes.forEach(({ type, componentOptions, props, children }) => {
      if (type && (type.toString() === 'Symbol(Fragment)' || type.toString() === 'Symbol()')) {
        Array.isArray(children) && children.forEach(({ type, componentOptions, props }) => handler({ type, componentOptions, props }))
      } else {
        handler({ type, componentOptions, props })
      }
    })
  }

  if (orders) {
    let tmpPanes = []

    orders.forEach((paneName) => {
      let pane = panes.find((pane) => pane.name === paneName)

      if (pane) tmpPanes.push(pane)
    })

    panes = tmpPanes
  }

  return panes
}

export default {
  name: $prefix + 'TabNav',
  components: {
    Popover,
    IconChevronLeft: iconChevronLeft(),
    IconChevronRight: iconChevronRight(),
    IconClose: iconClose()
  },
  props: {
    panes: {
      type: Array,
      default: () => []
    },
    currentName: String,
    editable: Boolean,
    onTabClick: {
      type: Function,
      default: () => {}
    },
    onTabRemove: {
      type: Function,
      default: () => {}
    },
    tabStyle: String,
    stretch: Boolean,
    showMoreTabs: Boolean,
    showPanesCount: Number,
    popperClass: String,
    popperAppendToBody: {
      type: Boolean,
      default: true
    },
    dropConfig: {
      type: Object,
      default: () => null
    }
  },
  setup(props, context) {
    return setup({ props, context, renderless, api, mono: true })
  },
  render() {
    const { state, tabStyle, editable, stretch, showPanesCount, onTabClick, onTabRemove, scrollNext, scrollPrev, changeTab } = this
    let { panes, setFocus, removeFocus, showMoreTabs, popperClass, popperAppendToBody } = this

    const spans = [
      <span class={['tiny-tabs__nav-prev', state.scrollable.prev ? '' : 'is-disabled']} onClick={scrollPrev}>
        <icon-chevron-left />
      </span>,
      !showMoreTabs ? (
        <span class={['tiny-tabs__nav-next', state.scrollable.next ? '' : 'is-disabled']} onClick={scrollNext}>
          <icon-chevron-right />
        </span>
      ) : null
    ]

    const scrollBtn = state.scrollable ? spans : null
    let moreTabs = null

    if (showMoreTabs && state.scrollable) {
      const reference = () => <span class="tiny-tabs__more">{t('ui.tabs.moreItem')}</span>

      const defaultSlot = () => (
        <ul>
          {~showPanesCount
            ? panes.slice(showPanesCount).map((pane, index) => {
                const tabName = pane.name || pane.state.index || index
                const tabLabelContent = pane.$slots.title || pane.title
                const tabindex = pane.state.active ? 0 : -1

                pane.state.index = `${index + showPanesCount}`

                return (
                  <li
                    class="tiny-tabs__more-item"
                    tabindex={tabindex}
                    onFocus={() => {
                      setFocus()
                    }}
                    onBlur={() => {
                      removeFocus()
                    }}
                    onClick={(e) => {
                      removeFocus()
                      onTabClick(pane, tabName, e)
                    }}
                  >
                    {typeof tabLabelContent === 'function' ? tabLabelContent() : tabLabelContent}
                  </li>
                )
              })
            : null}
        </ul>
      )

      moreTabs = (
        <div class="tiny-tabs__more-container">
          {' '}
          {h(Popover, {
            attrs: {
              popperClass: 'tiny-tabs__more-popover' + (popperClass ? ' ' + popperClass : ''),
              appendToBody: popperAppendToBody,
              placement: 'bottom-start',
              trigger: 'hover',
              width: 200,
              offset: -70,
              visibleArrow: true
            },
            scopedSlots: { reference, default: defaultSlot }
          })}{' '}
        </div>
      )
    }

    const tabs = getOrderedPanes(state, panes).map((pane, index) => {
      let tabName = pane.name || pane.state.index || index
      const withClose = pane.state.isClosable || editable

      pane.state.index = `${index}`

      const btnClose = withClose ? (
        <span class="tiny-tabs__icon-close">
          <icon-close
            onClick={(e) => {
              onTabRemove(pane, e)
            }}
          />
        </span>
      ) : null

      const tabLabelContent = pane.$slots.title ? pane.$slots.title() : pane.title
      const tabindex = pane.state.active ? 0 : -1

      return h(
        'div',
        {
          ref: `tabs-${tabName}`,
          key: `tab-${tabName}-${index}`,
          class: {
            'tiny-tabs__item': true,
            [`is-${state.rootTabs.position}`]: true,
            'is-active': pane.state.active,
            'is-disabled': pane.disabled,
            'is-closable': withClose,
            'is-focus': state.isFocus
          },
          attrs: {
            id: `tab-${tabName}`,
            'aria-controls': `pane-${tabName}`,
            role: 'tab',
            'aria-selected': pane.state.active,
            tabindex,
            refInFor: true
          },
          on: {
            focus() {
              setFocus()
            },
            blur() {
              removeFocus()
            },
            click(e) {
              removeFocus()
              onTabClick(pane, tabName, e)
            },
            keydown(e) {
              if (withClose && (e.keyCode === 46 || e.keyCode === 8)) {
                onTabRemove(pane, e)
              }
            }
          }
        },
        [tabLabelContent, btnClose]
      )
    })

    return (
      <div
        style={showMoreTabs ? { paddingRight: '46px' } : {}}
        class={['tiny-tabs__nav-wrap', state.scrollable ? 'is-scrollable' : '', showMoreTabs ? 'is-show-more' : '', `is-${state.rootTabs.position}`]}
      >
        {[scrollBtn, moreTabs]}
        <div class={['tiny-tabs__nav-scroll']} ref="navScroll">
          <div
            class={[
              'tiny-tabs__nav',
              `is-${state.rootTabs.position}`,
              stretch && ['top', 'bottom'].indexOf(state.rootTabs.position) !== -1 ? 'is-stretch' : '',
              !tabStyle ? 'is-show-active-bar' : ''
            ]}
            ref="nav"
            style={state.navStyle}
            role="tablist"
            on-keydown={changeTab}
          >
            {tabs}
          </div>
        </div>
      </div>
    )
  }
}
</script>
